effect 是 Vue 3 响应式系统的核心 API,它会立即执行一段函数,并在函数内部读取响应式数据时建立依赖关系;当这些响应式数据发生变化后,Vue 会自动重新执行对应的函数,从而实现视图更新、计算属性联动等功能。下面通过一个简化版源码,模拟 Vue 3 中 effect、reactive、依赖收集和派发更新的基本实现。
一、使用效果
我们希望实现下面这样的功能:
const state = reactive({
count: 0
})
effect(() => {
console.log('count:', state.count)
})
state.count++
// 输出:
// count: 0
// count: 1
当 effect 函数中读取了 state.count,系统就会记录依赖。当 state.count 被修改时,再次执行这个 effect。
二、简化版源码
// 用于保存当前正在执行的副作用函数
let activeEffect = null
// WeakMap<Object, Map<PropertyKey, Set<ReactiveEffect>>>
const targetMap = new WeakMap()
/**
* ReactiveEffect 类
* Vue 内部会将 effect 封装成一个 ReactiveEffect 实例
*/
class ReactiveEffect {
constructor(fn) {
this.fn = fn
// 当前 effect 依赖了哪些 Set
// 用于后续清理依赖
this.deps = []
this.active = true
}
run() {
if (!this.active) {
return this.fn()
}
// 清除之前收集的依赖
cleanupEffect(this)
// 设置当前正在执行的 effect
activeEffect = this
// 执行用户传入的函数
const result = this.fn()
// 执行完成后清空 activeEffect
activeEffect = null
return result
}
stop() {
if (this.active) {
cleanupEffect(this)
this.active = false
}
}
}
/**
* 清理 effect 之前收集的